package com;

import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Ricky
 * @date 2020-8-26
 */
@Service
@Slf4j
public class SocketIoServeice {
    /**
     * 用来存已连接的客户端
     */
    private final static Map<String, SocketIOClient> CLIENT_MAP = new ConcurrentHashMap<>();

    @Autowired
    private SocketIOServer socketIOServer;

    /**
     * Spring IoC容器创建之后，在加载SocketIOServiceImpl Bean之后启动
     */
    @PostConstruct
    private void autoStartup() {
        start();
    }

    /**
     * Spring IoC容器在销毁SocketIOServiceImpl Bean之前关闭,避免重启项目服务端口占用问题
     */
    @PreDestroy
    private void autoStop() {
        stop();
    }

    public void start() {
        // 监听客户端连接
        socketIOServer.addConnectListener(client -> {
            if (client != null) {
                String socketid = client.getSessionId().toString();
                CLIENT_MAP.put(socketid, client);
                log.info("有新客户端连接 {}，当前连接数量：{}", socketid, CLIENT_MAP.size());
                // 给客户端发送一条信息 发送ClientReceive事件 需要客户端绑定此事件即可接收到消息
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("name", "goat");
                jsonObject.put("message", "hello client");
                client.sendEvent("ClientReceive", jsonObject);

                client.sendEvent("cfwc", new JSONObject() {{
                    put("wjbh", "???");
                }});
            }
        });

        // 监听客户端断开
        socketIOServer.addDisconnectListener(client -> {
            String socketid = client.getSessionId().toString();
            CLIENT_MAP.remove(socketid);
            client.disconnect();
            log.info("一条客户端连接中断 {}，当前连接数量：{}", socketid, CLIENT_MAP.size());
        });

        // 处理自定义的事件，与连接监听类似
        // 此示例中测试的json收发 所以接收参数为JSONObject 如果是字符类型可以用String.class或者Object.class
        socketIOServer.addEventListener("ServerReceive", JSONObject.class, (client, data, ackSender) -> {
            // TODO do something
            String socketid = client.getSessionId().toString();
            log.info("接收到{}发来的消息:{}", socketid, data.toJSONString());
            ackSender.sendAckData(new JSONObject() {{
                put("res", "返回的数据");
            }});
        });
        socketIOServer.start();
        log.info("socket.io初始化服务完成");
    }

    public synchronized static void sendInfo(String socketid, String eventName, Object data) {
        if (StringUtils.isEmpty(socketid)) {
            for (String s : CLIENT_MAP.keySet()) {
                SocketIOClient client = CLIENT_MAP.get(s);
                client.sendEvent(eventName, data);
            }
        } else {
            SocketIOClient client = CLIENT_MAP.get(socketid);
            if (client != null) {
                client.sendEvent(eventName, data);
            }
        }
    }

    public void stop() {
        if (socketIOServer != null) {
            socketIOServer.stop();
            socketIOServer = null;
        }
        log.info("socket.io服务已关闭");
    }
}
